package me.kuye.jkuye.aop;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class InterceptorBuilder {
	private static final Interceptor[] NULL_INTERS = new Interceptor[0];

	private static Interceptor[] globalInters = NULL_INTERS;

	private static Map<Class<? extends Interceptor>, Interceptor> interceptorMap = new HashMap<Class<? extends Interceptor>, Interceptor>();

	public static Interceptor[] build(Interceptor[] injectIntercepors, Class<?> targetClass, Method method) {
		Interceptor[] methodInterceptor = createInterceptors(method.getAnnotation(Before.class));

		Clear clear = method.getAnnotation(Clear.class);

		if (clear == null) {
			Interceptor[] result = new Interceptor[globalInters.length + injectIntercepors.length
					+ methodInterceptor.length];
			int index = 0;
			for (Interceptor interceptor : globalInters) {
				result[index++] = interceptor;
			}
			for (Interceptor interceptor : methodInterceptor) {
				result[index++] = interceptor;
			}
			for (Interceptor interceptor : injectIntercepors) {
				result[index++] = interceptor;
			}
			return result;
		}

		Class<? extends Interceptor>[] clearClass = clear.value();

		if (clearClass.length == 0) {
			return methodInterceptor;
		}

		Interceptor[] classInters = createInterceptors(targetClass.getAnnotation(Before.class));
		Interceptor[] temp = new Interceptor[globalInters.length + injectIntercepors.length + classInters.length];
		int index = 0;
		for (Interceptor inter : globalInters)
			temp[index++] = inter;
		for (Interceptor inter : injectIntercepors)
			temp[index++] = inter;
		for (Interceptor inter : classInters)
			temp[index++] = inter;

		int removeCount = 0;
		for (int i = 0; i < temp.length; i++) {
			for (Class<? extends Interceptor> ci : clearClass) {
				if (temp[i].getClass() == ci) {
					temp[i] = null;
					removeCount++;
					break;
				}
			}
		}

		Interceptor[] result = new Interceptor[temp.length + methodInterceptor.length - removeCount];
		index = 0;
		for (Interceptor inter : temp)
			if (inter != null)
				result[index++] = inter;
		for (Interceptor inter : methodInterceptor)
			result[index++] = inter;
		return result;
	}

	private static Interceptor[] createInterceptors(Before before) {
		if (before == null) {
			return NULL_INTERS;
		}
		Class<? extends Interceptor>[] interceptorClass = before.value();
		if (interceptorClass.length == 0) {
			return NULL_INTERS;
		}
		Interceptor[] result = new Interceptor[interceptorClass.length];
		try {
			for (int i = 0; i < interceptorClass.length; i++) {
				result[i] = interceptorMap.get(interceptorClass[i]);
				if (result[i] == null) {
					result[i] = interceptorClass[i].newInstance();
					interceptorMap.put(interceptorClass[i], result[i]);
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return result;
	}

	public static synchronized void addGlobalServiceInterceptor(Interceptor... interceptors) {
		if (interceptors == null) {
			throw new IllegalArgumentException("the interceptors can not be null");
		}

		for (Interceptor inter : interceptors) {
			if (interceptorMap.containsKey(inter.getClass())) {
				throw new IllegalAccessError("the interceptor has been exist");
			}
		}
		for (Interceptor inter : interceptors) {
			interceptorMap.put(inter.getClass(), inter);
		}

		Interceptor[] temp = new Interceptor[globalInters.length + interceptors.length];
		System.arraycopy(globalInters, 0, temp, 0, globalInters.length);
		System.arraycopy(interceptors, 0, temp, globalInters.length, interceptors.length);
		globalInters = temp;

	}
}
